package com.wzh.core.consumer;

import com.google.common.base.Splitter;
import com.google.common.collect.Lists;
import com.wzh.core.annotation.RpcConsumer;
import com.wzh.core.api.LoadBalance;
import com.wzh.core.api.Router;
import com.wzh.core.api.RpcContent;
import com.wzh.core.api.entity.RpcException;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.EnvironmentAware;
import org.springframework.core.env.Environment;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Proxy;
import java.util.*;

/**
 * @description: 消费者启动类
 * @author: wangzouhuax
 */
public class ConsumerBootstrap implements ApplicationContextAware, EnvironmentAware {


    private ApplicationContext applicationContext;

    private Environment environment;

    private static final Map<String, Object> proxyMap = new HashMap<>();

    @Override
    public void setApplicationContext(@NotNull ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    /**
     * 扫描所有被 @RpcConsumer 注解的属性，并生成代理对象
     */
    public void screenConsumerServiceFields() {
        // 获取配置文件中的 provider
        String urls = environment.getProperty("rpc.provider");
        if (urls == null) {
            throw new RpcException("rpc.provider configuration is null");
        }
        List<String> providers = Lists.newArrayList(Splitter.on(",")
                .trimResults() // 去除空格
                .omitEmptyStrings() // 去除空字符串
                .split(urls));
        Router router = applicationContext.getBean(Router.class);
        LoadBalance loadBalance = applicationContext.getBean(LoadBalance.class);

        RpcContent rpcContent = RpcContent.create(router, loadBalance);
        // 获取所有 beanDefinitionNames
        String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
        // 获取所有 bean
        for (String beanDefinitionName : beanDefinitionNames) {
            Object bean = applicationContext.getBean(beanDefinitionName);
            // 获取所有被 @RpcConsumer 注解的属性
            // 此时获取到的Bean是增强后的 Bean，获取到的 userService 是代理对象, 即拿不到 userService上带有的 @RpcConsumer 注解
            List<Field> fieldList = findAnnotation(bean.getClass(), RpcConsumer.class);
            // 遍历所有注释的属性 生成代理对象
            fieldList.forEach(field -> {
                String serviceName = field.getType().getCanonicalName();
                // 获取代理对象 (被 @RpcConsumer 注解的属性)
                Object target = null;
                if (proxyMap.containsKey(serviceName)) {
                    target = proxyMap.get(serviceName);
                } else {
                    target = createProxyObject(field.getType(), rpcContent, providers);
                    proxyMap.put(serviceName, target);
                }
                try {
                    field.setAccessible(true);
                    field.set(bean, target);
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }

            });
        }
    }

    /**
     * 创建代理对象 使用JDK 动态代理
     */
    private Object createProxyObject(Class<?> clazz, RpcContent rpcContent, List<String> provider) {
        return Proxy.newProxyInstance(this.getClass().getClassLoader(),
                new Class[]{clazz},
                new RpcConsumerInvocationHandlerHandler(clazz.getCanonicalName(), rpcContent, provider));
    }


    /**
     * 获取所有被 @RpcConsumer 注解的属性
     *
     * @param clazz           所有 Bean 对象
     * @param annotationClass 要筛选的注解类
     * @return 符合条件的属性
     */
    public List<Field> findAnnotation(Class<?> clazz, Class<? extends Annotation> annotationClass) {
        List<Field> result = new ArrayList<>();
        // 处理继承关系
        while (Objects.nonNull(clazz)) {
            // 获取所有被 @RpcConsumer 注解的属性
            List<Field> fields = Arrays.stream(clazz.getDeclaredFields())
                    .filter(field -> field.isAnnotationPresent(annotationClass))
                    .toList();
            if (!fields.isEmpty()) {
                result.addAll(fields);
            }
            // 获取父类 - 获取到的 clazz 是被cglib 增强后的类
            clazz = clazz.getSuperclass();
        }
        return result;

    }

    @Override
    public void setEnvironment(@NotNull Environment environment) {
        this.environment = environment;
    }
}
